/** @file objects_dialog.cpp
    @brief Objects dialog functions */
#include "objects_dialog.h"

#include <QStandardItemModel>
#include <QFileDialog>
#include <QColorDialog>
#include <QString>

ObjectsDialog::ObjectsDialog( QWidget *parent ) :
    QDialog( parent )
{
    m_ignore_changes = false;
}

void ObjectsDialog::init() {
    // Setup UI
    setupUi( this );
    // Setup actions
    setupActions();

    std::string str;

    // Add colors
    add_colors();
}

void ObjectsDialog::setupActions() {
    // Connect to objectscript path changes
    QObject::connect( apply_button, SIGNAL( clicked() ), this, SLOT( apply_changes() ) );
    // Connect to objectscript path pick button
    QObject::connect( pick_object_path, SIGNAL( clicked() ), this, SLOT( pick_object() ) );
    // Connect to pixel color pick button
    QObject::connect( selected_color, SIGNAL( clicked() ), this, SLOT( pick_color() ) );
}

void ObjectsDialog::add_color( const Ogre::ColourValue &r_col ) {
    pm3::PIXELWORLD *world = pm3::PIXELWORLD::getSingletonPtr();
    pm3::PIXELOBJ *obj = NULL;
    QList< QStandardItem * > list;
    QStandardItem *item = NULL, *parent = NULL;

    // Get item model
    QStandardItemModel *model = ( QStandardItemModel * ) obj_list->model();

    if (!model)
        return;

    // Add all possible combinations of room exit directions
    for (int i = pm3::util::D_NONE; i < pm3::util::D_ALL; i++) {
        // Clear the list
        list.clear();

        // Set color item
        item = new QStandardItem();
        item->setBackground( QBrush( QColor::fromRgbF( r_col.r, r_col.g, r_col.b, r_col.a ) ) );
        // Add color
        list.append( item );

        // Add directions
        list.append( new QStandardItem( pm3::util::directions_to_str( i ).c_str() ) );

        // Add object paths
        {
            // Get object pointer
            obj = world->m_map.get_obj( r_col, i );
            // Is there such an object?
            if (obj) {
                // Add objectscript path
                list.append( new QStandardItem( obj->get_script().c_str() ) );
            } else {
                // Add empty string
                list.append( new QStandardItem( "" ) );
            }
        }

        // Group by color
        if (i == pm3::util::D_NONE) {
            // Add as a row
            model->appendRow( list );
            // Store parent
            parent = item;
        } else {
            // Add as a branch row
            parent->appendRow( list );
        }
    }
}

void ObjectsDialog::setupObjList() {
    // Get item model
    QStandardItemModel *model = ( QStandardItemModel * ) obj_list->model();
    // None? Create a new one..
    if (!model) {
        model = new QStandardItemModel( 0, 3 );

        // Set its headers
        model->setHeaderData( 0, Qt::Horizontal, QObject::tr("Color") );
        model->setHeaderData( 1, Qt::Horizontal, QObject::tr("Exits") );
        model->setHeaderData( 2, Qt::Horizontal, QObject::tr("Object") );

        // Assign the model to the list
        obj_list->setModel( model );

        // Set selection behavior
        obj_list->setSelectionMode( QAbstractItemView::SingleSelection );
        obj_list->setSelectionBehavior( QAbstractItemView::SelectRows );

        // Connect to selection changes
        QObject::connect( obj_list->selectionModel(), SIGNAL( selectionChanged( const QItemSelection &, const QItemSelection & ) ), 
                        this, SLOT( selection_changed( const QItemSelection &, const QItemSelection & ) ) );
    }
}

void ObjectsDialog::add_colors() {
    pm3::PIXELWORLD *world = pm3::PIXELWORLD::getSingletonPtr();
    int colors = world->m_map.num_colors();

    // Setup the list (just in case)
    setupObjList();

    // Add a color for clearing pixels
    add_color( Ogre::ColourValue( 0, 0, 0, 1 ) );

    // Add all colors
    for (int i=0; i<colors; i++)
        add_color( world->m_map.get_color( i ) );
}

void ObjectsDialog::clear_colors() {
    // Get model
    QStandardItemModel *model = ( QStandardItemModel * ) obj_list->model();
    // If there is such a model, then clear it
    if (model) {
        model->clear();

        obj_list->setModel( NULL );

        delete model;
    }

    setupObjList();
}

void ObjectsDialog::selection_changed( const QItemSelection &r_sel, const QItemSelection &r_desel ) {
    pm3::PIXELWORLD *world = pm3::PIXELWORLD::getSingletonPtr();
//    pm3::LOGGER *log = pm3::LOGGER::getSingletonPtr();
    pm3::PIXELOBJ *obj = NULL;
    // Get model
    QStandardItemModel *model = ( QStandardItemModel * ) obj_list->model();

    if (!model)
        return;

    QStandardItem *item = NULL;
    std::string str;
    QColor color;

    // Ignore changes due to selection
    m_ignore_changes = true;

    // Get color
    item = model->itemFromIndex( r_sel.indexes().at( 0 ) );
    if (item) {
        color = item->background().color();

        // Set stylesheet
        str = "background-color: rgb(";
        str += pm3::util::to_str( color.red() ) + ", ";
        str += pm3::util::to_str( color.green() ) + ", ";
        str += pm3::util::to_str( color.blue() ) + ");";

        selected_color->setStyleSheet( QString::fromUtf8( str.c_str() ) );
    }

    // Get directions
    item = model->itemFromIndex( r_sel.indexes().at( 1 ) );
    if (item)
        directions->setText( item->text() );

    // Get objectscript path
    item = model->itemFromIndex( r_sel.indexes().at( 2 ) );
    if (item)
        obj_path->setText( item->text() );

    // Get tags
    m_color = Ogre::ColourValue( color.redF(), color.greenF(), color.blueF(), color.alphaF() );
    color_tags->setPlainText( world->m_map.get_tags( m_color ).c_str() );
}

void ObjectsDialog::apply_changes() {
    pm3::PIXELWORLD *world = pm3::PIXELWORLD::getSingletonPtr();

    // Attempt an add_object with the new path
    world->m_map.add_object( m_color, directions->text().toStdString(), obj_path->text().toStdString() );
    // Attempt an add_color with the new tags
    world->m_map.add_color( m_color, color_tags->toPlainText().toStdString() );

    //! \todo Update objectlist in a more efficient way
    clear_colors();
    add_colors();
}

void ObjectsDialog::pick_object() {
    // Bring a file open dialog
    QDir dir( QDir::current() );
    QFileDialog qfile;
    qfile.setOption( QFileDialog::DontUseNativeDialog, true );
    qfile.setDirectory( dir );
    QString path = qfile.getOpenFileName();

    // Leave on empty path
    if (path.isEmpty())
      return;

    // Convert the path to canonical / relative form
    path = dir.relativeFilePath( path );

    // Set the path
    obj_path->setText( path );
}

void ObjectsDialog::pick_color() {
    QColor initial = QColor::fromRgbF( m_color.r, m_color.g, m_color.b, m_color.a );
    std::string str;
    QColor color;

    // Bring a color pick dialog
    color = QColorDialog::getColor( initial, this, "Pixel color" );
    // Color changed?
    if (color != initial) {
        // Update selected color
        m_color = Ogre::ColourValue( color.redF(), color.greenF(), color.blueF(), color.alphaF() );

        // Set selected color button stylesheet
        str = "background-color: rgb(";
        str += pm3::util::to_str( color.red() ) + ", ";
        str += pm3::util::to_str( color.green() ) + ", ";
        str += pm3::util::to_str( color.blue() ) + ");";

        selected_color->setStyleSheet( QString::fromUtf8( str.c_str() ) );
    }
}

